{
 "cells": [
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "### Building an Agentic RAG Workflow using Elasticsearch and LangChain",
   "id": "4f931c74dd212130"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "This notebook demonstrates a simple Agentic RAG workflow that uses Elasticsearch as the vector store and LangChain for orchestration. It accompanies the article \"Developing Adaptive Retrieval Workflows Using Elasticsearch and LangChain\" and showcases the core ideas discussed there. For a deeper explanation, please refer to the article.",
   "id": "a01126d74984e99d"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "### Prerequisites:\n",
    "\n",
    "This AgenticRAG example uses GPT-4.1 via AzureChatOpenAI, which requires certain environment variables to be configured.\n",
    "You can substitute any other LLM if preferred.\n",
    "\n",
    "You will be asked to set up the following environment variables:\n",
    "- AZURE_OPENAI_ENDPOINT\n",
    "- AZURE_OPENAI_KEY\n",
    "- AZURE_OPENAI_DEPLOYMENT\n",
    "- AZURE_OPENAI_API_VERSION\n",
    "- ES_ENDPOINT\n",
    "- ES_API_KEY"
   ],
   "id": "50dbf3b98f86609d"
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "f10b7273007fe477",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-27T16:07:42.075072Z",
     "start_time": "2025-10-27T16:07:42.073032Z"
    }
   },
   "outputs": [],
   "source": "!pip3 install langchain langgraph langchain-openai langchain-elasticsearch langchain-community datasets python-dotenv loguru elasticsearch \"pydantic>=2.0\" duckduckgo-search"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-06T16:31:43.953367Z",
     "start_time": "2025-11-06T16:31:43.949856Z"
    }
   },
   "cell_type": "code",
   "source": [
    "import time\n",
    "import getpass\n",
    "\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_core.output_parsers import StrOutputParser\n",
    "from langchain_core.runnables import RunnableSequence\n",
    "from langchain_openai import AzureChatOpenAI\n",
    "from langchain.chains import LLMChain, SequentialChain\n",
    "from datasets import load_dataset\n",
    "from langchain.schema import Document\n",
    "from langchain_elasticsearch import ElasticsearchStore, SparseVectorStrategy\n",
    "from langchain_community.tools import DuckDuckGoSearchRun\n",
    "from langgraph.graph import StateGraph, END, START\n",
    "from typing import TypedDict, List, Literal\n",
    "from loguru import logger\n",
    "from pydantic import BaseModel, Field\n",
    "from elasticsearch import Elasticsearch, NotFoundError, BadRequestError\n",
    "from IPython.display import Image"
   ],
   "id": "4965bea2b7d42736",
   "outputs": [],
   "execution_count": 64
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "### Set the environment variables",
   "id": "ae94daa7a83a719c"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-06T15:00:47.680922Z",
     "start_time": "2025-11-06T14:58:07.539524Z"
    }
   },
   "cell_type": "code",
   "source": [
    "ES_ENDPOINT = getpass.getpass(\"Enter Elastic Endpoint:  \")\n",
    "ES_API_KEY = getpass.getpass(\"Enter Elastic API Key:  \")"
   ],
   "id": "c7f50e08aa8339fc",
   "outputs": [],
   "execution_count": 32
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-06T15:03:01.414459Z",
     "start_time": "2025-11-06T15:02:35.251370Z"
    }
   },
   "cell_type": "code",
   "source": [
    "AZURE_OPENAI_ENDPOINT = getpass.getpass(\"Enter Azure OpenAI Endpoint:  \")\n",
    "AZURE_OPENAI_KEY = getpass.getpass(\"Enter Azure OpenAI Key:  \")\n",
    "AZURE_OPENAI_DEPLOYMENT = getpass.getpass(\"Enter Azure OpenAI Deployment:  \")\n",
    "AZURE_OPENAI_API_VERSION = getpass.getpass(\"Enter Azure OpenAI API Version:  \")"
   ],
   "id": "4a3aae6e2f03bce5",
   "outputs": [],
   "execution_count": 33
  },
  {
   "cell_type": "markdown",
   "id": "9223ae18-d05e-4aa1-9bce-456deae748bc",
   "metadata": {},
   "source": [
    "### Install ELSER"
   ]
  },
  {
   "cell_type": "code",
   "id": "7f722ca314787202",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-06T15:10:14.749049Z",
     "start_time": "2025-11-06T15:10:14.742933Z"
    }
   },
   "source": [
    "es = Elasticsearch(hosts=[ES_ENDPOINT], api_key=ES_API_KEY, request_timeout=3600)"
   ],
   "outputs": [],
   "execution_count": 44
  },
  {
   "cell_type": "code",
   "id": "4533e737a820eac",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-06T15:05:28.989252Z",
     "start_time": "2025-11-06T15:05:28.981178Z"
    }
   },
   "source": [
    "def install_elser(es: Elasticsearch, model_id: str):\n",
    "    try:\n",
    "        es.ml.get_trained_models(model_id=model_id)\n",
    "    except NotFoundError:\n",
    "        logger.info(f'\"{model_id}\" not found. Installing...')\n",
    "        es.ml.put_trained_model(\n",
    "            model_id=model_id, input={\"field_names\": [\"text_field\"]}\n",
    "        )\n",
    "\n",
    "    while True:\n",
    "        status = es.ml.get_trained_models(\n",
    "            model_id=model_id, include=\"definition_status\"\n",
    "        )\n",
    "        if status[\"trained_model_configs\"][0][\"fully_defined\"]:\n",
    "            break\n",
    "        time.sleep(1)\n",
    "\n",
    "    stats = es.ml.get_trained_models_stats(model_id=model_id)\n",
    "    allocation_state = (\n",
    "        stats[\"trained_model_stats\"][0]\n",
    "        .get(\"deployment_stats\", {})\n",
    "        .get(\"allocation_status\", {})\n",
    "        .get(\"state\")\n",
    "    )\n",
    "    if allocation_state != \"fully_allocated\":\n",
    "        try:\n",
    "            es.ml.start_trained_model_deployment(\n",
    "                model_id=model_id, wait_for=\"fully_allocated\"\n",
    "            )\n",
    "        except BadRequestError:\n",
    "            pass\n",
    "\n",
    "    logger.info(f'\"{model_id}\" model is ready')"
   ],
   "outputs": [],
   "execution_count": 37
  },
  {
   "cell_type": "code",
   "id": "e008bd7c76211926",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-06T15:05:52.481140Z",
     "start_time": "2025-11-06T15:05:31.120714Z"
    }
   },
   "source": [
    "install_elser(es, \".elser_model_2\")"
   ],
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001B[32m2025-11-06 10:05:52.472\u001B[0m | \u001B[1mINFO    \u001B[0m | \u001B[36m__main__\u001B[0m:\u001B[36minstall_elser\u001B[0m:\u001B[36m22\u001B[0m - \u001B[1m\".elser_model_2\" model is ready\u001B[0m\n"
     ]
    }
   ],
   "execution_count": 38
  },
  {
   "cell_type": "markdown",
   "id": "5b249dda2266361c",
   "metadata": {},
   "source": [
    "### Define your LLM"
   ]
  },
  {
   "cell_type": "code",
   "id": "b2978186bbc9b333",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-06T15:30:35.343351Z",
     "start_time": "2025-11-06T15:30:35.333574Z"
    }
   },
   "source": [
    "llm = AzureChatOpenAI(\n",
    "    azure_deployment=AZURE_OPENAI_DEPLOYMENT,\n",
    "    azure_endpoint=AZURE_OPENAI_ENDPOINT,\n",
    "    api_version=AZURE_OPENAI_API_VERSION,\n",
    "    api_key=AZURE_OPENAI_KEY,\n",
    ")"
   ],
   "outputs": [],
   "execution_count": 58
  },
  {
   "cell_type": "markdown",
   "id": "941ea7193b81b224",
   "metadata": {},
   "source": [
    "#### Load AG news dataset"
   ]
  },
  {
   "cell_type": "code",
   "id": "2d1526b3a04fdae",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-06T15:06:27.518833Z",
     "start_time": "2025-11-06T15:06:26.485649Z"
    }
   },
   "source": [
    "dataset = load_dataset(\"ag_news\", split=\"train[:1000]\")\n",
    "docs = [\n",
    "    Document(page_content=sample[\"text\"], metadata={\"category\": sample[\"label\"]})\n",
    "    for sample in dataset\n",
    "]"
   ],
   "outputs": [],
   "execution_count": 40
  },
  {
   "cell_type": "markdown",
   "id": "c83d573c1e63a5c7",
   "metadata": {},
   "source": [
    "#### Add documents to Elasticsearch vector store"
   ]
  },
  {
   "cell_type": "code",
   "id": "d78b4e82ff95374d",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-06T15:07:58.647936Z",
     "start_time": "2025-11-06T15:07:53.046956Z"
    }
   },
   "source": [
    "index_name = \"news_docs\"\n",
    "elastic_vectorstore = ElasticsearchStore.from_documents(\n",
    "    docs,\n",
    "    es_url=ES_ENDPOINT,\n",
    "    es_api_key=ES_API_KEY,\n",
    "    es_params={\"request_timeout\": 60, \"max_retries\": 3, \"retry_on_timeout\": True},\n",
    "    index_name=index_name,\n",
    "    strategy=SparseVectorStrategy(model_id=\".elser_model_2\"),\n",
    ")\n",
    "\n",
    "elastic_vectorstore.client.indices.refresh(index=index_name)"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ObjectApiResponse({'_shards': {'total': 2, 'successful': 2, 'failed': 0}})"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 41
  },
  {
   "cell_type": "markdown",
   "id": "3d3e09d4ad4a3cf4",
   "metadata": {},
   "source": [
    "### Define your data retrieval options"
   ]
  },
  {
   "cell_type": "code",
   "id": "da8d9fe9f790020d",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-06T15:25:29.026797Z",
     "start_time": "2025-11-06T15:25:29.022842Z"
    }
   },
   "source": [
    "def vectorstore_retriever(query, k=5):\n",
    "    results = elastic_vectorstore.similarity_search_with_score(query, k=k)\n",
    "    docs = [doc for doc, score in results]\n",
    "    related_docs = \"\\n\".join([d.page_content for d in docs])\n",
    "    return related_docs\n",
    "\n",
    "\n",
    "duckduckgo = DuckDuckGoSearchRun(\n",
    "    description=\"A custom DuckDuckGo search tool for finding latest news stories.\",\n",
    "    verbose=True,\n",
    ")\n",
    "\n",
    "\n",
    "def websearch_retriever(query):\n",
    "    results = duckduckgo.run(f\"{query}\")\n",
    "    return results\n",
    "\n",
    "\n",
    "def composite_retriever(query):\n",
    "    related_docs = vectorstore_retriever(query)\n",
    "    related_docs += websearch_retriever(query)\n",
    "    return related_docs"
   ],
   "outputs": [],
   "execution_count": 46
  },
  {
   "cell_type": "markdown",
   "id": "8bb186748e2c93af",
   "metadata": {},
   "source": [
    "### Define your LLM Chains"
   ]
  },
  {
   "cell_type": "code",
   "id": "d232c7529e549b8a",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-06T15:30:40.787403Z",
     "start_time": "2025-11-06T15:30:40.779749Z"
    }
   },
   "source": [
    "class RouteQuery(BaseModel):\n",
    "    datasource: Literal[\"vectorstore\", \"websearch\", \"composite\"] = Field(\n",
    "        ...,\n",
    "        description=\"Choose to route the query to web search, vectorstore or composite.\",\n",
    "    )\n",
    "\n",
    "\n",
    "router_prompt = ChatPromptTemplate.from_template(\n",
    "    \"\"\"You are an assistant that decides the best data source for questions based on news articles.\n",
    "Choose one of the following options:\n",
    "- 'vectorstore': for general, background, or historical news articles.\n",
    "- 'websearch': for recent discoveries, 'latest', 'current', or '2025' type queries.\n",
    "- 'composite': when the question needs both historical and current knowledge on news articles.\n",
    "\n",
    "Question: {query}\n",
    "\n",
    "Return one word: 'vectorstore', 'websearch', or 'composite'.\n",
    "\"\"\"\n",
    ")\n",
    "router_structured = llm.with_structured_output(RouteQuery)\n",
    "router_chain: RunnableSequence = router_prompt | router_structured\n",
    "\n",
    "\n",
    "class GradeRetrievedDocs(BaseModel):\n",
    "    binary_score: bool = Field(\n",
    "        description=\"True if retrieved documents match the query intent, False otherwise.\"\n",
    "    )\n",
    "\n",
    "\n",
    "grade_retrieved_docs_prompt = ChatPromptTemplate.from_template(\n",
    "    \"\"\"\n",
    "You are an evaluator that determines whether the retrieved documents are relevant to the given user query.\n",
    "\n",
    "Instructions:\n",
    "- Compare the intent and information need of the query against the retrieved documents.\n",
    "- Answer only 'True' or 'False'.\n",
    "- 'True' means the retrieved documents align with the query’s intent and can likely answer it.\n",
    "- 'False' means the retrieved documents do not address the main topic or intent of the query.\n",
    "\n",
    "Return only one word: 'True' or 'False'.\n",
    "\n",
    "Query:\n",
    "{query}\n",
    "\n",
    "Retrieved Documents:\n",
    "{docs}\n",
    "\"\"\"\n",
    ")\n",
    "\n",
    "retrieved_docs_structured = llm.with_structured_output(GradeRetrievedDocs)\n",
    "grade_docs_chain: RunnableSequence = (\n",
    "    grade_retrieved_docs_prompt | retrieved_docs_structured\n",
    ")\n",
    "\n",
    "\n",
    "class RewrittenQuery(BaseModel):\n",
    "    query: str\n",
    "\n",
    "\n",
    "rewrite_query_prompt = ChatPromptTemplate.from_template(\n",
    "    \"\"\"\n",
    "The grader returned that the retrieved documents do not answer the query. Reformulate the query to better capture the user's intent and retrieve relevant information. Return ONLY the rewritten query, concise and clear. Just the string i.e. the rewritten query.\n",
    "\n",
    "Original Query:\n",
    "{query}\n",
    "\"\"\"\n",
    ")\n",
    "rewritten_query_structured = llm.with_structured_output(RewrittenQuery)\n",
    "rewrite_query_chain: RunnableSequence = (\n",
    "    rewrite_query_prompt | rewritten_query_structured\n",
    ")\n",
    "\n",
    "summarize_prompt = ChatPromptTemplate.from_template(\n",
    "    \"\"\"You are a helpful news assistant. Your task is to summarize the retrieved news articles in a concise and accurate way that directly answers the user's query.\n",
    "User Query:\n",
    "{query}\n",
    "\n",
    "Retrieved Articles:\n",
    "{docs}\n",
    "\n",
    "Instructions:\n",
    "- Focus on the most relevant information that answers the query.\n",
    "- Do not include unrelated details.\n",
    "- Present the summary in clear, coherent sentences.\n",
    "- If multiple articles provide overlapping information, combine them without repetition.\n",
    "\n",
    "Summary:\"\"\"\n",
    ")\n",
    "summarize_chain = LLMChain(\n",
    "    llm=llm, prompt=summarize_prompt, output_parser=StrOutputParser()\n",
    ")"
   ],
   "outputs": [],
   "execution_count": 59
  },
  {
   "cell_type": "markdown",
   "id": "4cfeb8887f95122d",
   "metadata": {},
   "source": [
    "### Start building the StateGraph"
   ]
  },
  {
   "cell_type": "code",
   "id": "9db64c1fe48f0f0",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-06T15:30:45.063493Z",
     "start_time": "2025-11-06T15:30:45.056921Z"
    }
   },
   "source": [
    "class RAGState(TypedDict):\n",
    "    query: str\n",
    "    docs: List[Document]\n",
    "    router: str\n",
    "    summary: str\n",
    "    self_reflection: bool\n",
    "    retry_count: int = 0\n",
    "\n",
    "\n",
    "def router(state: RAGState):\n",
    "    router = router_chain.invoke({\"query\": state[\"query\"]})\n",
    "    logger.info(f\"Router selected the datasource: {router.datasource}\")\n",
    "    logger.info(f\"User query: {state['query']}\")\n",
    "    return {\"router\": router.datasource}\n",
    "\n",
    "\n",
    "def vectorstore(state: RAGState):\n",
    "    return {\"docs\": vectorstore_retriever(state[\"query\"])}\n",
    "\n",
    "\n",
    "def websearch(state: RAGState):\n",
    "    return {\"docs\": websearch_retriever(state[\"query\"])}\n",
    "\n",
    "\n",
    "def composite(state: RAGState):\n",
    "    return {\"docs\": composite_retriever(state[\"query\"])}\n",
    "\n",
    "\n",
    "def self_reflection(state: RAGState):\n",
    "    evaluation = grade_docs_chain.invoke(\n",
    "        {\"query\": state[\"query\"], \"docs\": state[\"docs\"]}\n",
    "    )\n",
    "    if evaluation.binary_score:\n",
    "        logger.info(f\"Self-reflection passed — binary_score={evaluation.binary_score}\")\n",
    "    else:\n",
    "        logger.info(f\"Self-reflection failed — binary_score={evaluation.binary_score}\")\n",
    "\n",
    "    return {\n",
    "        \"self_reflection\": evaluation.binary_score,\n",
    "    }\n",
    "\n",
    "\n",
    "def query_rewriter(state: RAGState):\n",
    "    retry_count = state.get(\"retry_count\", 0) + 1\n",
    "    new_query = rewrite_query_chain.invoke({\"query\": state[\"query\"]})\n",
    "    logger.info(f\"Query rewritten: {new_query}, retry_count: {retry_count}\")\n",
    "    return {\n",
    "        \"query\": new_query,\n",
    "        \"retry_count\": retry_count,\n",
    "    }\n",
    "\n",
    "\n",
    "def summarize(state: RAGState):\n",
    "    summary = summarize_chain.run(\n",
    "        query=state[\"query\"],\n",
    "        docs=state[\"docs\"],\n",
    "    )\n",
    "    return {\"summary\": summary}"
   ],
   "outputs": [],
   "execution_count": 60
  },
  {
   "cell_type": "markdown",
   "id": "5b4d7a4121b7593b",
   "metadata": {},
   "source": [
    "### Build Graph with LangChain"
   ]
  },
  {
   "cell_type": "code",
   "id": "16c2b13c6e782184",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-06T15:30:47.573930Z",
     "start_time": "2025-11-06T15:30:47.492874Z"
    }
   },
   "source": [
    "graph = StateGraph(RAGState)\n",
    "\n",
    "graph.add_node(\"router\", router)\n",
    "graph.add_node(\"vectorstore\", vectorstore)\n",
    "graph.add_node(\"websearch\", websearch)\n",
    "graph.add_node(\"composite\", composite)\n",
    "graph.add_node(\"self_reflection\", self_reflection)\n",
    "graph.add_node(\"query_rewriter\", query_rewriter)\n",
    "graph.add_node(\"summarize\", summarize)\n",
    "\n",
    "graph.add_edge(START, \"router\")\n",
    "\n",
    "\n",
    "def after_router(state: RAGState):\n",
    "    route = state.get(\"router\", None)\n",
    "    if route == \"vectorstore\":\n",
    "        return \"vectorstore\"\n",
    "    elif route == \"websearch\":\n",
    "        return \"websearch\"\n",
    "    else:\n",
    "        return \"composite\"\n",
    "\n",
    "\n",
    "def after_self_reflection(state: RAGState):\n",
    "    if state[\"self_reflection\"]:\n",
    "        return \"summarize\"\n",
    "    return \"query_rewriter\"\n",
    "\n",
    "\n",
    "def after_query_rewriter(state: RAGState):\n",
    "    while state[\"retry_count\"] <= 3:\n",
    "        return \"router\"\n",
    "    raise RuntimeError(\"Maximum retries (3) reached — evaluation failed.\")\n",
    "\n",
    "\n",
    "graph.add_conditional_edges(\n",
    "    \"router\",\n",
    "    after_router,\n",
    "    {\"vectorstore\": \"vectorstore\", \"websearch\": \"websearch\", \"composite\": \"composite\"},\n",
    ")\n",
    "\n",
    "graph.add_edge(\"vectorstore\", \"self_reflection\")\n",
    "graph.add_edge(\"websearch\", \"self_reflection\")\n",
    "graph.add_edge(\"composite\", \"self_reflection\")\n",
    "graph.add_conditional_edges(\n",
    "    \"self_reflection\",\n",
    "    after_self_reflection,\n",
    "    {\"summarize\": \"summarize\", \"query_rewriter\": \"query_rewriter\"},\n",
    ")\n",
    "graph.add_conditional_edges(\n",
    "    \"query_rewriter\", after_query_rewriter, {\"router\": \"router\"}\n",
    ")\n",
    "graph.add_edge(\"summarize\", END)\n",
    "agent = graph.compile()\n",
    "agent.get_graph().draw_mermaid_png(output_file_path=\"graph.png\")\n",
    "Image(\"graph.png\")"
   ],
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 61
  },
  {
   "cell_type": "markdown",
   "id": "4c64b15457ddd328",
   "metadata": {},
   "source": [
    "### Start testing"
   ]
  },
  {
   "cell_type": "code",
   "id": "5c787b2428e926ca",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-06T15:30:51.624639Z",
     "start_time": "2025-11-06T15:30:51.622118Z"
    }
   },
   "source": [
    "query1 = \"What are the latest AI models released this month?\"\n",
    "query2 = \"What technological innovations are discussed in Sci/Tech news?\"\n",
    "query3 = \"Compare a Sci/Tech article from the dataset with a current web article about AI trends.\""
   ],
   "outputs": [],
   "execution_count": 62
  },
  {
   "cell_type": "code",
   "id": "3c48705d7c0d237c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-06T15:31:00.392467Z",
     "start_time": "2025-11-06T15:30:52.982336Z"
    }
   },
   "source": [
    "result = agent.invoke({\"query\": query1})\n",
    "logger.info(f\"\\nFinal Summary:\\n: {result['summary']}\")"
   ],
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001B[32m2025-11-06 10:30:53.873\u001B[0m | \u001B[1mINFO    \u001B[0m | \u001B[36m__main__\u001B[0m:\u001B[36mrouter\u001B[0m:\u001B[36m11\u001B[0m - \u001B[1mRouter selected the datasource: websearch\u001B[0m\n",
      "\u001B[32m2025-11-06 10:30:53.874\u001B[0m | \u001B[1mINFO    \u001B[0m | \u001B[36m__main__\u001B[0m:\u001B[36mrouter\u001B[0m:\u001B[36m12\u001B[0m - \u001B[1mUser query: What are the latest AI models released this month?\u001B[0m\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001B[32;1m\u001B[1;3mWhat Is The Best AI Model In September 2025? Ultimate Comparison The five most powerful AI companies have now unveiled their flagship models , creating what might be the most intense competition we've seen in artificial intelligence development. OpenAI dropped GPT-5 in early August 2025, while Anthropic released Claude Opus 4.1 just days earlier. Here's what I've learned after testing every major AI release this month : The real question isn't about keeping up with every shiny new model . It's about how to use AI tools responsibly while they rapidly evolve around us. Missed the latest AI news? From ChatGPT upgrades to Google's new tools, here are 7 big AI updates you need to know about this week. To fully meet our goals, MAI requires purpose-built models . Today, we're excited to preview the first steps to making this a reality. First, we're releasing MAI-Voice-1, our first highly expressive and natural speech generation model , which is available in Copilot Daily and Podcasts, and as a brand new Copilot Labs experience to try out here. Anthropic has unveiled its latest AI models , Claude Opus 4 and Claude Sonnet 4, marking a significant advancement in the field of artificial intelligence. Claude Opus 4 stands out as Anthropic's most powerful model to date, excelling in complex coding tasks and long-duration problem-solving.\u001B[0m"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001B[32m2025-11-06 10:30:58.545\u001B[0m | \u001B[1mINFO    \u001B[0m | \u001B[36m__main__\u001B[0m:\u001B[36mself_reflection\u001B[0m:\u001B[36m29\u001B[0m - \u001B[1mSelf-reflection passed — binary_score=True\u001B[0m\n",
      "\u001B[32m2025-11-06 10:31:00.390\u001B[0m | \u001B[1mINFO    \u001B[0m | \u001B[36m__main__\u001B[0m:\u001B[36m<module>\u001B[0m:\u001B[36m2\u001B[0m - \u001B[1m\n",
      "Final Summary:\n",
      ": The latest AI models released this month include OpenAI's GPT-5, launched in early August 2025, and Anthropic's Claude Opus 4.1, alongside Claude Opus 4 and Claude Sonnet 4, which feature advanced capabilities in coding and long-duration problem-solving. Additionally, MAI unveiled MAI-Voice-1, a highly expressive speech generation model, now available in Copilot applications. These releases mark significant advancements from leading AI companies.\u001B[0m\n"
     ]
    }
   ],
   "execution_count": 63
  },
  {
   "cell_type": "code",
   "id": "a63de923-ca7b-42fb-9a80-7f261cb92d74",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-06T15:29:16.249050Z",
     "start_time": "2025-11-06T15:29:13.321002Z"
    }
   },
   "source": [
    "result = agent.invoke({\"query\": query2})\n",
    "logger.info(f\"\\nFinal Summary:\\n: {result['summary']}\")"
   ],
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001B[32m2025-11-06 10:29:14.260\u001B[0m | \u001B[1mINFO    \u001B[0m | \u001B[36m__main__\u001B[0m:\u001B[36mrouter\u001B[0m:\u001B[36m11\u001B[0m - \u001B[1mRouter selected the datasource: vectorstore\u001B[0m\n",
      "\u001B[32m2025-11-06 10:29:14.261\u001B[0m | \u001B[1mINFO    \u001B[0m | \u001B[36m__main__\u001B[0m:\u001B[36mrouter\u001B[0m:\u001B[36m12\u001B[0m - \u001B[1mUser query: What technological innovations are discussed in Sci/Tech news?\u001B[0m\n",
      "/Users/kirtisodhi/Library/Python/3.9/lib/python/site-packages/langchain_elasticsearch/_sync/vectorstores.py:530: ElasticsearchWarning: text_expansion is deprecated. Use sparse_vector instead.\n",
      "  hits = self._store.search(\n",
      "\u001B[32m2025-11-06 10:29:14.771\u001B[0m | \u001B[1mINFO    \u001B[0m | \u001B[36m__main__\u001B[0m:\u001B[36mself_reflection\u001B[0m:\u001B[36m29\u001B[0m - \u001B[1mSelf-reflection passed — binary_score=True\u001B[0m\n",
      "\u001B[32m2025-11-06 10:29:16.247\u001B[0m | \u001B[1mINFO    \u001B[0m | \u001B[36m__main__\u001B[0m:\u001B[36m<module>\u001B[0m:\u001B[36m2\u001B[0m - \u001B[1m\n",
      "Final Summary:\n",
      ": Recent Sci/Tech news highlights several technological innovations: NASA is developing a cutting-edge Linux-based supercomputer to support researchers and shuttle engineers; a company has achieved cat cloning through chromatin transfer technology; Princeton University scientists report that current technologies can be implemented immediately to stabilize global warming for the next 50 years; and a set of innovative GameBoy mini-games has won a prize for game design.\u001B[0m\n"
     ]
    }
   ],
   "execution_count": 54
  },
  {
   "cell_type": "code",
   "id": "24c342fa-8220-42b6-adf3-b48fcd164104",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-06T15:29:42.898171Z",
     "start_time": "2025-11-06T15:29:37.639301Z"
    }
   },
   "source": [
    "result = agent.invoke({\"query\": query3})\n",
    "logger.info(f\"\\nFinal Summary:\\n: {result['summary']}\")"
   ],
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001B[32m2025-11-06 10:29:38.534\u001B[0m | \u001B[1mINFO    \u001B[0m | \u001B[36m__main__\u001B[0m:\u001B[36mrouter\u001B[0m:\u001B[36m11\u001B[0m - \u001B[1mRouter selected the datasource: composite\u001B[0m\n",
      "\u001B[32m2025-11-06 10:29:38.535\u001B[0m | \u001B[1mINFO    \u001B[0m | \u001B[36m__main__\u001B[0m:\u001B[36mrouter\u001B[0m:\u001B[36m12\u001B[0m - \u001B[1mUser query: Compare a Sci/Tech article from the dataset with a current web article about AI trends.\u001B[0m\n",
      "/Users/kirtisodhi/Library/Python/3.9/lib/python/site-packages/langchain_elasticsearch/_sync/vectorstores.py:530: ElasticsearchWarning: text_expansion is deprecated. Use sparse_vector instead.\n",
      "  hits = self._store.search(\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001B[32;1m\u001B[1;3m3 days ago - In the late 2010s, graphics processing ... large-scale (commercial and academic) machine learning models' training. Specialized programming languages such as Prolog were used in early AI research, but general-purpose programming languages like Python have become predominant. The transistor density in integrated circuits has been observed to roughly double every 18 months—a trend known as Moore's ... May 1, 2025 - Models with advanced reasoning capabilities, like OpenAI o1, can already solve complex problems with logical steps that are similar to how humans think before responding to difficult questions. These capabilities will continue to be useful in fields like science, coding, math, law and medicine, allowing models to compare contracts, generate code and execute multistep workflows. 2 days ago - In any given business function, no more than 10 percent of respondents say their organizations are scaling AI agents (Exhibit 2). Looking at individual business functions, agent use is most commonly reported in IT and knowledge management, where agentic use cases such as service-desk management in IT and deep research in knowledge management have quickly developed. By industry, the use of AI agents is most widely reported in the technology, media and telecommunications, and healthcare sectors (Exhibit 3). 1 month ago - North America, which includes the U.S. and Canada, is the market leader . In 2023, it captured 38.9% of the global AI market, which was about $97.25 billion in revenue. ... China has a much higher active adoption rate. March 4, 2025 - AI Statistics explores the latest trends in artificial intelligence (AI). Gain insights into adoption rates, AI jobs, and applications.\u001B[0m"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001B[32m2025-11-06 10:29:40.618\u001B[0m | \u001B[1mINFO    \u001B[0m | \u001B[36m__main__\u001B[0m:\u001B[36mself_reflection\u001B[0m:\u001B[36m29\u001B[0m - \u001B[1mSelf-reflection passed — binary_score=True\u001B[0m\n",
      "\u001B[32m2025-11-06 10:29:42.894\u001B[0m | \u001B[1mINFO    \u001B[0m | \u001B[36m__main__\u001B[0m:\u001B[36m<module>\u001B[0m:\u001B[36m2\u001B[0m - \u001B[1m\n",
      "Final Summary:\n",
      ": The Sci/Tech article from the dataset highlights NASA's development of advanced AI for planetary rovers, aiming to make them more autonomous and capable of making mission-critical decisions independently. This reflects a trend towards specialized AI applications in science and exploration.\n",
      "\n",
      "Compared to current web articles on AI trends, the broader industry focus is on scaling AI models and agents across various sectors, especially in IT, healthcare, and knowledge management. Recent models like OpenAI o1 showcase advanced reasoning, supporting complex tasks in coding, law, and medicine. While organizations are experimenting with AI agents, widespread deployment is still limited. The global AI market continues to grow, with North America as a leader and China rapidly adopting AI solutions.\n",
      "\n",
      "In summary, while NASA’s AI efforts demonstrate specialized, mission-focused intelligence in robotics, current AI trends emphasize the expansion of advanced, general-purpose AI agents across industries to boost productivity and handle complex workflows. Both reflect ongoing technical progress and increasing real-world impact of artificial intelligence.\u001B[0m\n"
     ]
    }
   ],
   "execution_count": 56
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
